package com.apes.fn.scm.retailOrder.service.account.retail;

import com.apes.crm.business.model.InsuranceCompanyDetail;
import com.apes.fn.business.fixedLoss.service.FixedLossToForeign;
import com.apes.fn.scm.insuranceRules.InsuranceRule;
import com.apes.fn.scm.insuranceRules.InsuranceRuleService;
import com.apes.fn.scm.retailOrder.model.RetailOrder;
import com.apes.fn.scm.retailOrder.service.account.BackBatchAndSupplierService;
import com.apes.fn.scm.retailOrder.service.account.RetailAccountData;
import com.apes.fn.server.servicePlan.model.ServicePlanItem;
import com.apes.fn.server.servicePlan.repository.ServicePlanItemRepository;
import com.apes.fn.server.servicePlan.service.ServicePlanceService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.util.MapUtil;
import com.apes.framework.util.ReflectUtil;
import com.apes.scm.account.tax.model.Tax;
import com.apes.scm.account.tax.service.TaxService;
import com.apes.scm.contract.model.Contract;
import com.apes.scm.contract.service.ContractService;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.sal.saleOrder.SaleOrder;
import com.apes.scm.voucher.model.Voucher;
import com.apes.scm.voucher.model.VoucherInventory;
import com.apes.scm.voucher.model.VoucherItem;
import com.apes.scm.voucher.repository.VoucherInventoryRepository;
import com.apes.scm.voucher.service.BusinessType;
import com.apes.scm.voucher.service.VoucherType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 定损生成凭证服务
 *
 * @Author wuq
 * @Date 2021-8-2
 */
@RetailAccount(value = "insurance", name = "定损凭证")
@Service
public class InsuranceVoucherService extends BackBatchAndSupplierService {

    @Autowired
    private ServicePlanItemRepository servicePlanItemRepository;
    @Autowired
    private ServicePlanceService servicePlanceService;
    @Autowired
    private TaxService taxService;
    @Autowired
    private ContractService contractService;
    @Autowired
    private VoucherInventoryRepository voucherInventoryRepository;

    public void process(RetailAccountData retailAccountData) {
        RetailOrder retailOrder = retailAccountData.getRetailOrder();

        InsuranceRule insuranceRule = SpringManager.getBean(InsuranceRuleService.class)
                .findByDeptAndInsuranceCompany(retailOrder.getServiceDept(), retailOrder.getInsuranceCompany());
        if (Objects.isNull(insuranceRule) && retailOrder.getInsuranceCompany().isCooperation()) {
            throw new RuntimeException("没有找到对应的车型规则，部门：" + retailOrder.getServiceDept().getId() + "，保险公司：" + retailOrder.getInsuranceCompany().getId());
        }

        // 增加控制 车险规则为空 + 非合作保险公司  直接对保险公司销售
        if (Objects.isNull(insuranceRule) && !retailOrder.getInsuranceCompany().isCooperation()) {
            createInsuranceSale(retailOrder);
            return;
        }

        // 存在车险规则： 判断基地公司是否能直接对保险公司开票
        if (retailOrder.getServiceDept().getCompany().getId().equals(insuranceRule.getCompany().getId())) {
            /** 直接生成对保险公司的分销单 **/
            createInsuranceSale(retailOrder);
        } else {
            /** 不能对保险公司开票，找定损规则上面的公司开票 **/
            createCrossInsuranceSale(retailOrder, insuranceRule.getCompany());
        }
    }

    private void createInsuranceSale(RetailOrder retailOrder) {
        List array = getServicePlanList(retailOrder);
        invoke("innerServicePlan.create.autoReturn", array);    // 自动归还

        // 通过保险公司明细找保险公司客户
        InsuranceCompanyDetail companyDetail = SpringManager.getBean(FixedLossToForeign.class)
                .getInsuranceCompanyToClient(retailOrder.getInsuranceCompany(), retailOrder.getServiceDept());

        // 创建销售订单（自动审核）
        Map param = MapUtil.mapper("deptId", retailOrder.getServiceDept().getId(),
                "companyId", retailOrder.getServiceDept().getCompany().getId(),
                "customerId", companyDetail.getClient().getId(),
                "source", retailOrder.getId(), "items", array);
        List<SaleOrder> saleOrderList = invoke("innerServicePlan.create.saleOrder", param);
        saleOrderList.forEach(saleOrder -> {
            invoke("saleOrderFlow.create.productOutput", MapUtil.mapped(saleOrder));    // 销售订单商品出库
            invoke("saleOrderFlow.create.voucher", MapUtil.mapped(saleOrder));          // 创建销售凭证以及账单
        });
    }

    private void createCrossInsuranceSale(RetailOrder retailOrder, PartyRole insuranceSaleCompany) {
        // 创建基地对销售公司的分销单
        createStoreSaleOrder(retailOrder, insuranceSaleCompany);

        // 销售公司采购与对保险公司的销售
        Voucher voucher = createBasePurchase(retailOrder, insuranceSaleCompany);
        createBaseInsuranceSale(voucher, retailOrder);
    }

    public void saleCompanyVoucher(RetailOrder retailOrder, PartyRole insuranceSaleCompany) {
        // 销售公司采购与对保险公司的销售
        Voucher voucher = createBasePurchase(retailOrder, insuranceSaleCompany);
        createBaseInsuranceSale(voucher, retailOrder);
    }

    private void createStoreSaleOrder(RetailOrder retailOrder, PartyRole insuranceSaleCompany) {
        List array = getServicePlanList(retailOrder);
        invoke("innerServicePlan.create.autoReturn", array);    // 自动归还

        // 创建销售订单（自动审核）
        Map param = MapUtil.mapper("deptId", retailOrder.getServiceDept().getId(),
                "companyId", retailOrder.getServiceDept().getCompany().getId(),
                "customerId", insuranceSaleCompany.getParty().getPatyRoleByType("Customer").getId(),
                "source", retailOrder.getId(), "items", array);
        List<SaleOrder> saleOrderList = invoke("innerServicePlan.create.saleOrder", param);
        saleOrderList.forEach(saleOrder -> {
            invoke("saleOrderFlow.create.productOutput", MapUtil.mapped(saleOrder));    // 销售订单商品出库
            invoke("saleOrderFlow.create.voucher", MapUtil.mapped(saleOrder));          // 创建销售凭证以及账单
        });
    }

    private Voucher createBasePurchase(RetailOrder retailOrder, PartyRole insuranceSaleCompany) {
        // 生成带安采购凭证
        Voucher purVoucher = new Voucher();
        purVoucher.setScene(retailOrder.getScene());

        PartyRole company = insuranceSaleCompany.getParty().getPartyRoleByType("Company");
        purVoucher.setCompany(company);
        purVoucher.setPartner(retailOrder.getServiceDept().getCompany().getParty().getPatyRoleByType("Supplier"));
        Dept dept = getDept(purVoucher.getCompany());
        purVoucher.setDept(dept);     // 采购部门

        Contract contract = contractService.getContract(purVoucher.getDept(), purVoucher.getPartner(), "distribution", "supplier", "定损卖单销售业务");
        purVoucher.setContract(contract);
        purVoucher.setInventoryMode(purVoucher.getContract().getCooperation().getInventoryMode());     //设置库存模式：寄售
        purVoucher.setAccountingMethod(purVoucher.getContract().getCooperation().getAccountingMethod());  // 核算方式：采购价

        purVoucher.setCustomerExpand(retailOrder.getCustomerExpand().getId());
        purVoucher.setClerk(retailOrder.getClerk()); //业务员
        purVoucher.setClassification(VoucherType.INSURANCE);

        purVoucher.setBusinessType(BusinessType.PURCHASE_ORDER);
        purVoucher.setOrigin(retailOrder.getId());
        purVoucher.setOriginBusinessType(retailOrder.getInnerBusinessType());
        purVoucher.setSource(retailOrder.getId());
        purVoucher.setSourceBusinessType(retailOrder.getInnerBusinessType());

        PartyRole supplier = purVoucher.getPartner();
        purVoucher.setVoucherItems(
                retailOrder.getSaleItems().stream().map(
                        item -> {
                            VoucherItem voucherItem = new VoucherItem();
                            ReflectUtil.copy(item, voucherItem, "product", "uom", "priceUnit");

                            voucherItem.setProductQty(item.getProductUomQty());
                            voucherItem.setOriginItemId(item.getId());
                            voucherItem.setSourceItemId(item.getId());
                            voucherItem.setOwner(company);
                            voucherItem.setDiscount(0d);
                            Tax tax = taxService.getPurchaseTax(company, supplier, item.getProduct());   //供应商进项税
                            voucherItem.setTax(tax);
                            voucherItem.setInnerSalePriceUnit(item.getInnerSalePriceUnit());    // 公司间交易价
                            return voucherItem;
                        }
                ).collect(Collectors.toSet()));
        purVoucher = invoke("voucher.create", MapUtil.mapped(purVoucher));

        changeFrostQty(purVoucher, "定损流程生成，基地对门店的采购凭证");

        //生成账单
        createInvoiceAndFixOriginNumber(retailOrder, purVoucher);
        return purVoucher;
    }

    private void createBaseInsuranceSale(Voucher purVoucher, RetailOrder retailOrder) {
        Voucher voucher = new Voucher();
        voucher.setBusinessType(BusinessType.SALE_ORDER);

        ReflectUtil.copy(purVoucher, voucher, "dept", "company", "clerk", "scene", "customerExpand");

        // 通过保险公司明细找保险公司客户
        InsuranceCompanyDetail companyDetail = SpringManager.getBean(FixedLossToForeign.class)
                .getInsuranceCompanyToClient(retailOrder.getInsuranceCompany(), retailOrder.getServiceDept());
        voucher.setPartner(companyDetail.getClient());

        Contract contract = contractService.getContract(voucher.getDept(), voucher.getPartner(), "distribution", "customer", "定损卖单销售业务");
        voucher.setContract(contract);
        voucher.setInventoryMode(voucher.getContract().getCooperation().getInventoryMode());     //设置库存模式
        voucher.setAccountingMethod(voucher.getContract().getCooperation().getAccountingMethod());  // 核算方式
        voucher.setCustomerExpand(retailOrder.getCustomerExpand().getId());
        voucher.setClassification(VoucherType.INSURANCE);

        voucher.setSource(purVoucher.getId());
        voucher.setSourceBusinessType(purVoucher.getInnerBusinessType());
        voucher.setOrigin(retailOrder.getId());
        voucher.setOriginBusinessType(retailOrder.getInnerBusinessType());

        voucher.setVoucherItems(
                retailOrder.getSaleItems().stream().map(
                        retailOrderItem -> {
                            VoucherItem voucherItem = new VoucherItem();
                            ReflectUtil.copy(retailOrderItem, voucherItem, "product", "uom", "priceUnit");

                            voucherItem.setProductQty(retailOrderItem.getProductUomQty());
                            voucherItem.setOriginItemId(retailOrderItem.getId());
                            voucherItem.setSourceItemId(retailOrderItem.getId());
                            voucherItem.setDiscount(0d);

                            Tax tax = taxService.getSaleTax(purVoucher.getCompany(), retailOrderItem.getProduct());
                            voucherItem.setTax(tax);

                            voucherItem.setOwner(purVoucher.getCompany());
                            return voucherItem;
                        }).collect(Collectors.toSet())
        );
        double lossQuotationFeeAmt = voucher.getVoucherItems().stream().mapToDouble(VoucherItem::getLossQuotationFee).sum();
        voucher.setLossQuotationFeeAmt(lossQuotationFeeAmt);

        // 添加采购凭证批次以及供应商信息
        voucher.getVoucherItems().forEach(item -> {
            purVoucher.getVoucherItems().forEach(purchaseVoucherItem -> {

                VoucherInventory voucherInventory = voucherInventoryRepository.findByVoucherItem(purchaseVoucherItem).stream()
                        .findAny().orElseThrow(() -> new RuntimeException("找不到批次信息！"));

                if (item.getProduct().getId().equals(voucherInventory.getProduct().getId())) {
                    item.setInventoryBatch(voucherInventory.getInventoryBatch());
                    item.setSupplier(purchaseVoucherItem.getSupplier());
                }
            });
        });

        // 创建账单
        voucher = invoke("voucher.create", MapUtil.mapped(voucher));

        //增加账单
        createInvoiceAndFixOriginNumber(retailOrder, voucher);
    }


    /**
     * 找到基地对应的方案明细
     *
     * @param retailOrder RetailOrder
     * @return List<Map>
     */
    private List getServicePlanList(RetailOrder retailOrder) {
        List<ServicePlanItem> servicePlanItems = new ArrayList<>();

        retailOrder.getSaleItems().forEach(item -> {
            ServicePlanItem planItem = servicePlanItemRepository.findOne(item.getOriginnumber());
            if (retailOrder.getServiceDept().getId().equals(retailOrder.getDept().getId())) {   // 基地自己接车自己定损
                servicePlanItems.add(planItem);
            } else {
                ServicePlanItem basePlanItem = servicePlanceService.findCBPForServicePlan(planItem);
                if (basePlanItem == null)
                    throw new RuntimeException("定损销售流程，根据门店方案未找到对应内协门店方案，门店方案号为：" + planItem.getId());
                servicePlanItems.add(basePlanItem);
            }
        });
        return MapUtil.mapped(servicePlanItems);
    }

}
